package io.awen.modules.sign.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.awen.common.utils.DistanceUtil;
import io.awen.common.utils.PageUtils;
import io.awen.common.utils.Query;
import io.awen.modules.sign.dao.SignCarWeightChangeDao;
import io.awen.modules.sign.entity.*;
import io.awen.modules.sign.qo.SignCarWeightChangeQo;
import io.awen.modules.sign.qo.SignTaskQo;
import io.awen.modules.sign.service.*;
import io.awen.modules.sys.entity.SysUserEntity;
import io.awen.modules.sys.service.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.messaging.simp.SimpMessageHeaderAccessor.getUser;


/**
 * 通过载重量判断车辆在卸货、装货
 * (SignCarSpeedingWarning)表服务实现类
 */
@Service("SignCarWeightChangeService")
public class SignCarWeightChangeServiceImpl extends ServiceImpl<SignCarWeightChangeDao, SignCarWeightChangeEntity> implements SignCarWeightChangeService {

    @Autowired
    private SignCarService signCarService;

    @Autowired
    private SignCarWeightChangeService signCarWeightChangeService;

    @Autowired
    private SignCarLonLatService signCarLonLatService;

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SignContainerService signContainerService;

    @Autowired
    private SignSinkService signSinkService;

    @Autowired
    private SignFleetService signFleetService;



    @Override
    public void insertWhenWeightChange(SignCarEntity car, Double Speed, String Weight, Double lon, Double lat) {
        //拿到速度，和sign_car_lon_lat中对应的相同car_id的最新的一条记录的speed值相比较
        //如果此时的速度为0，而上一条的速度不为0，则在表里插进一条数据，字段state为0，表示状态没有完成标记，并插入开始时间的字段和weight字段
        //如果此时的速度不为0，而上一条的速度为0，则取表里的最后一条state为0的数据，更新字段state为1，且此时的字段和之前的weight差距大，表示状态完成标记，并插入结束时间的字段
        //速度不为0时，速度差距不大，则表示车辆没有在装卸货物，state更新为3，表示此时状态为停车无操作

        if (car != null && Weight != null) {
            SignCarLonLatEntity carLonLat = signCarLonLatService.getOne(new QueryWrapper<SignCarLonLatEntity>()
                    .eq("car_id", car.getId())
                    .orderByDesc("id")
                    .last("limit 1,1"));
            if (Speed == 0) {

                if (carLonLat.getSpeed() != 0) {
//                    System.out.println("两个速度 = " + Speed + " " + carLonLat.getSpeed());

                    SignCarWeightChangeEntity entity = new SignCarWeightChangeEntity();
                    entity.setSignCarId(car.getId());
                    entity.setSignCarNumberPlate(car.getNumberPlate());
                    entity.setLon(lon);
                    entity.setLat(lat);
                    entity.setStartWeight(Weight);
                    entity.setState(0);
                    this.save(entity);

                }
            } else {
                if (carLonLat.getSpeed() == 0) {
                    SignCarWeightChangeEntity weightChange = signCarWeightChangeService.getOne(new QueryWrapper<SignCarWeightChangeEntity>()
                            .eq("sign_car_id", car.getId())
                            .orderByDesc("id")
                            .last("limit 1"));
                    if (weightChange != null && weightChange.getState() == 0) {
                        double change = Double.parseDouble(weightChange.getStartWeight()) - Double.parseDouble(Weight);
                        if (change > 1000) {
                            // 有效卸水
                            weightChange.setState(2);
                            weightChange.setEndWeight(Weight);
                            this.updateById(weightChange);
                            List<SignSinkEntity> sinks = signSinkService.list();
                            Long sinkId = DistanceUtil.getNearestSinkId(lon, lat, sinks);
                            if (sinkId != null) {
                                weightChange.setSinkId(sinkId);
//                                System.out.println("sinkId = " + sinkId);
                            }
                            this.updateById(weightChange);
                            SignCarWeightChangeEntity start = signCarWeightChangeService.getOne(new QueryWrapper<SignCarWeightChangeEntity>()
                                    .eq("sign_car_id", weightChange.getSignCarId())
                                    .eq("state", 1)//装货的过滤出来
                                    .orderByDesc("id")
                                    .last("limit 1"));
                            List<SignCarLonLatEntity> list = signCarLonLatService.list(new QueryWrapper<SignCarLonLatEntity>()
                                    .eq("car_id", weightChange.getSignCarId())
                                    .ge("create_time", start.getUpdateTime())
                                    .le("create_time", weightChange.getCreateTime())
                                    .orderByAsc("id"));
                            double distance = 0;
                            for (int i = 0; i < list.size() - 1; i++) {
                                distance += DistanceUtil.getDistance(list.get(i).getLon(), list.get(i).getLat(), list.get(i + 1).getLon(), list.get(i + 1).getLat());
                            }
                            weightChange.setDistance(distance);
                            this.updateById(weightChange);

                        } else if (change < -1000) {
                            weightChange.setState(1);
                            weightChange.setEndWeight(Weight);
                            //通过当前记录的经纬度，查询sign_container表中最近的一个经纬度，并且距离小于10米，将这个经纬度的container_id赋值给这条记录
                            //查询sign_container表中最近的一个经纬度，并且距离小于10米
                            List<SignContainerEntity> containers = signContainerService.list();
                            Long containerId = DistanceUtil.getNearestContainerId(lon, lat, containers);
                            if (containerId != null) {
                                weightChange.setContainerId(containerId);
                                this.updateById(weightChange);
                            }
                        } else {
                            //删除这条记录
                            this.removeById(weightChange.getId());

                        }
                    }
                }
            }
        }
    }

    @Override
    public List<Map<String, Object>> weightTotalGroupByContainer(SignCarWeightChangeQo qo) {
        List<Map<String, Object>> mapList = this.listMaps(
                new QueryWrapper<SignCarWeightChangeEntity>()
                        .select("container_id as containerId, sum(end_weight) as syWeight, sum(TIMESTAMPDIFF(second, start_time, end_time)) as lostTime, count(id) weightCount")
                        .eq("state", "1")
                        .eq(qo.getContainerId() != null, "container_id", qo.getContainerId())
                        .in(qo.getContainerIdList() != null && qo.getContainerIdList().size() > 0, "container_id", qo.getContainerIdList())
                        .ge(qo.getStartTime() != null, "create_time", qo.getStartTime())
                        .le(qo.getEndTime() != null, "create_time", qo.getEndTime())
                        .groupBy("container_id")
                        .orderBy(StringUtils.isNotBlank(qo.getOrder()), "1".equals(qo.getOrder()), "syWeight")
        );

        for (Map<String, Object> map : mapList) {
            SignContainerEntity container = signContainerService.findContainer((Long) map.get("containerId"));
            if (container != null) {
                map.put("containerName", container.getName());
            }
        }

        return mapList;
    }

    @Override
    public PageUtils queryLedger(SignCarWeightChangeQo qo) {
        IPage<SignCarWeightChangeEntity> page = signCarWeightChangeService.page(
                new Query<SignCarWeightChangeEntity>().getPage(qo),
                new QueryWrapper<SignCarWeightChangeEntity>().lambda()
                        .eq(qo.getState() != null, SignCarWeightChangeEntity::getState, qo.getState())
                        .eq(qo.getSignCarId() != null, SignCarWeightChangeEntity::getSignCarId, qo.getSignCarId())
                        .ge(qo.getStartTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getStartTime())
                        .le(qo.getEndTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getEndTime())
                        .orderByDesc(SignCarWeightChangeEntity::getCreateTime)
        );

        List<SignCarWeightChangeEntity> records = page.getRecords();
        List<Map<String, Object>> resultList = new ArrayList<>();

        for (SignCarWeightChangeEntity record : records) {
            Map<String, Object> row = new HashMap<>();
            row.put("id", record.getId());
            row.put("sign_car_id", record.getSignCarId());
            row.put("container_id", record.getContainerId());
            row.put("start_weight", record.getStartWeight());
            row.put("create_time", record.getCreateTime());

            QueryWrapper<SignCarWeightChangeEntity> prevWrapper = new QueryWrapper<>();
            prevWrapper.eq("sign_car_id", record.getSignCarId());
            prevWrapper.eq("state", 2);
            prevWrapper.gt("create_time", record.getCreateTime());
            prevWrapper.orderByAsc("create_time");
            prevWrapper.last("LIMIT 1");

            SignCarWeightChangeEntity prev = signCarWeightChangeService.getOne(prevWrapper);
            if (prev != null) {
                row.put("distance", prev.getDistance());
                row.put("end_weight", prev.getStartWeight());
                row.put("end_time", prev.getCreateTime());

                QueryWrapper<SignContainerEntity> containerWrapper = new QueryWrapper<>();
                containerWrapper.eq("id", prev.getContainerId());
                SignContainerEntity container = signContainerService.getById(record.getContainerId());
                if (container != null) {
                    row.put("container_name", container.getName());
                    row.put("period", container.getPeriod());
                    row.put("sheqv", container.getSheqv());
                }

                QueryWrapper<SignSinkEntity> sinkWrapper = new QueryWrapper<>();
                sinkWrapper.eq("id", prev.getSinkId());
                SignSinkEntity sink = signSinkService.getOne(sinkWrapper);
                if (sink != null) {
                    row.put("sink_names", sink.getName());
                }
            }

            resultList.add(row);
        }

        return new PageUtils(resultList, (int) page.getTotal(), (int) page.getSize(), (int) page.getCurrent());
    }
//    @Override
//    public PageUtils totalTable(SignCarWeightChangeQo qo) {
//        IPage<SignCarWeightChangeEntity> page = signCarWeightChangeService.page(
//                new Query<SignCarWeightChangeEntity>().getPage(qo),
//                new QueryWrapper<SignCarWeightChangeEntity>().lambda()
//                        .eq(qo.getState() != null, SignCarWeightChangeEntity::getState, qo.getState())
//                        .eq(qo.getSignCarId() != null, SignCarWeightChangeEntity::getSignCarId, qo.getSignCarId())
//                        .ge(qo.getStartTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getStartTime())
//                        .le(qo.getEndTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getEndTime())
//                        .orderByDesc(SignCarWeightChangeEntity::getCreateTime)
//        );
//
//        List<SignCarWeightChangeEntity> records = page.getRecords();
//        List<Map<String, Object>> resultList = new ArrayList<>();
//
//        for (SignCarWeightChangeEntity record : records) {
//            Map<String, Object> row = new HashMap<>();
//            row.put("id", record.getId());
//            row.put("sign_car_id", record.getSignCarId());
//            row.put("container_id", record.getContainerId());
//            row.put("start_weight", record.getStartWeight());
//            row.put("create_time", record.getCreateTime());
//            SignCarEntity car = signCarService.getById(record.getSignCarId());
//            SysUserEntity user = sysUserService.getById(car.getDriverId());
//            if (user != null) {
//                row.put("driver_name", user.getUsername());
//                row.put("driver_phone", user.getMobile());
//            }
//
//            QueryWrapper<SignCarWeightChangeEntity> prevWrapper = new QueryWrapper<>();
//            prevWrapper.eq("sign_car_id", record.getSignCarId());
//            prevWrapper.eq("state", 2);
//            prevWrapper.gt("create_time", record.getCreateTime());
//            prevWrapper.orderByAsc("create_time");
//            prevWrapper.last("LIMIT 1");
//
//            SignCarWeightChangeEntity prev = signCarWeightChangeService.getOne(prevWrapper);
//            if (prev != null) {
//                row.put("distance", prev.getDistance());
//                row.put("end_weight", prev.getStartWeight());
//                row.put("end_time", prev.getCreateTime());
//
//                QueryWrapper<SignContainerEntity> containerWrapper = new QueryWrapper<>();
//                containerWrapper.eq("id", prev.getContainerId());
//                SignContainerEntity container = signContainerService.getById(record.getContainerId());
//                if (container != null) {
//                    row.put("container_name", container.getName());
//                    row.put("period", container.getPeriod());
//                    row.put("sheqv", container.getSheqv());
//                    row.put("container_address", container.getContainerAddress());
//                    SignFleetEntity fleet = signFleetService.getById(container.getCtFleetId());
//                    row.put("fleet_name", fleet.getFleetName());
//                }
//
//                QueryWrapper<SignSinkEntity> sinkWrapper = new QueryWrapper<>();
//                sinkWrapper.eq("id", prev.getSinkId());
//                SignSinkEntity sink = signSinkService.getOne(sinkWrapper);
//                if (sink != null) {
//                    row.put("sink_names", sink.getName());
//                }
//            }
//
//            resultList.add(row);
//        }
//
//        return new PageUtils(resultList, (int) page.getTotal(), (int) page.getSize(), (int) page.getCurrent());
//    }

    @Override
    public PageUtils totalTable(SignCarWeightChangeQo qo) {
        IPage<SignCarWeightChangeEntity> page = this.page(
                new Query<SignCarWeightChangeEntity>().getPage(qo),
                new QueryWrapper<SignCarWeightChangeEntity>().lambda()
                        .eq(SignCarWeightChangeEntity::getState, 1)
                        .ge(qo.getStartTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getStartTime())
                        .le(qo.getEndTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getEndTime())
                        .orderByDesc(SignCarWeightChangeEntity::getId)
        );
        for (SignCarWeightChangeEntity entity : page.getRecords()) {
            //查找时间比当前记录时间大的，state为2的一条记录
            QueryWrapper<SignCarWeightChangeEntity> prevWrapper = new QueryWrapper<>();
            prevWrapper.eq("sign_car_id", entity.getSignCarId());
            prevWrapper.eq("state", 2);
            prevWrapper.gt("create_time", entity.getCreateTime());
            prevWrapper.last("LIMIT 1");
            SignCarWeightChangeEntity prev = signCarWeightChangeService.getOne(prevWrapper);
            if (prev != null) {
                SignSinkEntity sink = signSinkService.getById(prev.getSinkId());
                entity.setSignSinkEntity(sink);
                entity.setEndWeight(prev.getStartWeight());
                entity.setDistance(prev.getDistance());
                entity.setSinkId(prev.getSinkId());
            } else {
                entity.setEndWeight("0");
                entity.setDistance(0.0);
                entity.setSinkId(null);
            }
            SignContainerEntity container = signContainerService.getById(entity.getContainerId());
            if (container != null) {
                entity.setSignContainerEntity(container);
            }
            entity.setSignCarEntity(signCarService.getById(entity.getSignCarId()));
            SignFleetEntity fleet = signFleetService.getById(entity.getSignCarEntity().getFleetId());
            entity.setSignFleetEntity(fleet);
            SysUserEntity user = sysUserService.getById(entity.getSignCarEntity().getDriverId());
            entity.setUserEntity(user);
        }
//        定义一个数组
        Map<String, SignCarWeightChangeEntity> mergedEntities = new HashMap<>();

        for (SignCarWeightChangeEntity entity : page.getRecords()) {
            @Deprecated
            int newDay = entity.getCreateTime().getYear() + entity.getCreateTime().getMonth() + entity.getCreateTime().getDay();
            String key = entity.getSignCarId() + "-" + entity.getContainerId() + "-" + entity.getSinkId() + "-" + newDay;
            SignCarWeightChangeEntity mergedEntity = mergedEntities.get(key);
            if (mergedEntity == null) {
                // If the merged entity doesn't exist yet, create a new one
                mergedEntity = new SignCarWeightChangeEntity();
                mergedEntity.setId(entity.getId());
                mergedEntity.setCreateTime(entity.getCreateTime());
                mergedEntity.setStartWeight(entity.getStartWeight());
                mergedEntity.setSignContainerEntity(entity.getSignContainerEntity());
                mergedEntity.setSignSinkEntity(entity.getSignSinkEntity());
                mergedEntity.setSignCarEntity(entity.getSignCarEntity());
                mergedEntity.setSignCarId(entity.getSignCarId());
                mergedEntity.setContainerId(entity.getContainerId());
                mergedEntity.setSinkId(entity.getSinkId());
                mergedEntity.setEndWeight(entity.getEndWeight());
                mergedEntity.setDistance(entity.getDistance());
                mergedEntity.setSignFleetEntity(entity.getSignFleetEntity());
                mergedEntity.setCount(entity.getCount());
                mergedEntity.setUserEntity(entity.getUserEntity());
                mergedEntities.put(key, mergedEntity);

            } else {
                // If the merged entity already exists, update its values
                mergedEntity.setEndWeight(String.valueOf(Double.parseDouble(mergedEntity.getEndWeight()) + Double.parseDouble(entity.getEndWeight())));
                mergedEntity.setDistance(mergedEntity.getDistance() + entity.getDistance());
                //给mergedEntity创建一个属性，用来记录合并的次数
                mergedEntity.setCount(mergedEntity.getCount() + 1);
            }
        }
        //将合并后的数据放入page中
        page.setRecords(new ArrayList<>(mergedEntities.values()));
//        return new PageUtils(mergedEntities.values().stream().collect(Collectors.toList()), (int) page.getTotal(), (int) page.getSize(), (int) page.getCurrent());
        return new PageUtils(page);
    }


    @Override
    public PageUtils queryPage(SignCarWeightChangeQo qo) {
        IPage<SignCarWeightChangeEntity> page = this.page(
                new Query<SignCarWeightChangeEntity>().getPage(qo),
                new QueryWrapper<SignCarWeightChangeEntity>().lambda()
                        .eq(qo.getState() != null, SignCarWeightChangeEntity::getState, qo.getState())
                        .eq(qo.getSignCarId() != null, SignCarWeightChangeEntity::getSignCarId, qo.getSignCarId())
                        .like(StringUtils.isNotBlank(qo.getSignCarNumberPlate()), SignCarWeightChangeEntity::getSignCarNumberPlate, qo.getSignCarNumberPlate())
                        .ge(qo.getStartTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getStartTime())
                        .le(qo.getEndTime() != null, SignCarWeightChangeEntity::getCreateTime, qo.getEndTime())
                        .orderByDesc(SignCarWeightChangeEntity::getCreateTime)
        );
        for (SignCarWeightChangeEntity entity : page.getRecords()) {
            SignCarEntity car = signCarService.getById(entity.getSignCarId());
            if (car != null) {
                SysUserEntity user = sysUserService.getById(car.getDriverId());
                entity.setUserEntity(user);
            }
            entity.setSignCarEntity(car);
        }

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageWeightTotalGroupByCar(SignCarWeightChangeQo qo) {

        List<Map<String, Object>> list = this.weightTotalGroupByCar(qo);

        IPage<Map<String, Object>> page = new Query<Map<String, Object>>().getPage(qo);
        //当前页
        long current = page.getCurrent();
        //每页数据条数
        long size = page.getSize();
        int count = list.size();
        List<Map<String, Object>> pageList = new ArrayList<>();
        //计算当前页第一条数据的下标
        long currId = current > 1 ? (current - 1) * size : 0;
        for (int i = 0; i < size && i < count - currId; i++) {
            pageList.add(list.get((int) currId + i));
        }
        page.setSize(size);
        page.setCurrent(current);
        page.setTotal(count);
        //计算分页总页数
        page.setPages(count % 10 == 0 ? count / 10 : count / 10 + 1);
        page.setRecords(pageList);

        return new PageUtils(page);

    }

    @Override
    public List<Map<String, Object>> weightTotalGroupByCar(SignCarWeightChangeQo qo) {
        List<Map<String, Object>> mapList = this.listMaps(
                new QueryWrapper<SignCarWeightChangeEntity>()
                        .select("sign_car_number_plate AS signCarNumberPlate, sign_car_id as signCarId, sum(start_weight) as syWeight,sum(distance) as distance, sum(TIMESTAMPDIFF(second, create_time, update_time)) as lostTime, count(id) taskCount")
                        .eq("state", 2)
                        .in(qo.getCarIdList() != null && qo.getCarIdList().size() > 0, "sign_car_id", qo.getCarIdList())
                        .ge(qo.getStartTime() != null, "update_time", qo.getStartTime())
                        .le(qo.getEndTime() != null, "update_time", qo.getEndTime())
                        .groupBy("sign_car_id,sign_car_number_plate")
                        .orderBy(StringUtils.isNotBlank(qo.getOrder()), "1".equals(qo.getOrder()), "syWeight")
        );

        return mapList;
    }

    @Override
    public List<Map<String, Object>> weightTotalGroupByTimeLength(SignCarWeightChangeQo qo) {
        List<Map<String, Object>> mapList = this.listMaps(
                new QueryWrapper<SignCarWeightChangeEntity>()
                        .select("SUBSTR(update_time, 1, " + qo.getTimeLength() + ") data_time, sum(start_weight) as syWeight, sum(TIMESTAMPDIFF(second, create_time, update_time)) as lostTime, count(id) taskCount")
                        .eq("state", 2)
                        .ge(qo.getStartTime() != null, "update_time", qo.getStartTime())
                        .le(qo.getEndTime() != null, "update_time", qo.getEndTime())
                        .groupBy("data_time")
                        .orderBy(StringUtils.isNotBlank(qo.getOrder()), "1".equals(qo.getOrder()), "data_time")
        );
        return mapList;
    }

    public void submit(SignCarWeightChangeEntity qo) {
        //创建一个新的
        SignCarWeightChangeEntity entity = new SignCarWeightChangeEntity();

//        System.out.println(qo);
//        System.out.println(qo.getSignCarId());
        entity.setSignCarId(qo.getSignCarId());
        entity.setSignCarNumberPlate(qo.getSignCarNumberPlate());
        entity.setLat(qo.getLat());
        entity.setLon(qo.getLon());
        entity.setState(qo.getState());
//        BeanUtils.copyProperties(qo, entity);
        if (qo.getState() == 1) {
            //装货
            entity.setStartWeight("0");
            entity.setEndWeight("5000");
            entity.setCreateTime(new Date());
            entity.setUpdateTime(new Date());
            entity.setDeleteFlag(0L);
            entity.setBind(0);
            //找到最近的收集池
            List<SignContainerEntity> containers = signContainerService.list();
            Long containerId = DistanceUtil.getNearestContainerId(entity.getLon(), entity.getLat(), containers);
            entity.setContainerId(containerId);

        } else if (qo.getState() == 2) {
            entity.setStartWeight("5000");
            entity.setEndWeight("0");
            entity.setCreateTime(new Date());
            entity.setUpdateTime(new Date());
            entity.setDeleteFlag(0L);
            entity.setBind(0);
            //找到最近的卸水点
            List<SignSinkEntity> sinks = signSinkService.list();
            Long sinkId = DistanceUtil.getNearestSinkId(entity.getLon(), entity.getLat(), sinks);
            entity.setSinkId(sinkId);
        }
        this.save(entity);
    }
}